﻿using Api.index;
using JiebaNet.Segmenter;
using System.Web;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using JiebaNet.Segmenter.Common;

namespace Api.index
{
    class WordCount
    {
        // 词在标题中出现的次数
        public int titleCount=0;
        // 词在正文中出现的次数
        public int contentCount=0;
    }
    public class Index
    {
        public static Index index=new Index();
        static List<DocInfo> forwardIndex = new List<DocInfo>();
        private static Dictionary<string, List<Weight>> invertedIndex = new Dictionary<string, List<Weight>>();
        // 1. 给定一个 docId，在正排索引中，查询文档的详细信息
        public DocInfo getDocInfo(int docId)
        {
            return forwardIndex[docId];
        }

        // 2. 给定一个词，在倒排索引中，查哪些文档和这个词关联
        // 因为 文档和词之间存在一定的相关性，所以返回值应和权重有关
        public List<Weight> getInverted(string term)
        {
            return invertedIndex.GetOrDefault(term);
        }

        // 3. 往索引中新增一个文档
        public void addDoc(string title, string url, string content)
        {
            // 新增文档操作，需要同时给正排索引和倒排索引新增信息
            // 构建正排索引
            DocInfo docInfo = buildForward(title, url, content);
            // 构建倒排索引
            buildInverted(docInfo);
        }

        private DocInfo buildForward(string title, string url, string content)
        {
            DocInfo docInfo = new DocInfo(forwardIndex.Capacity, title, url, content);
            docInfo.setDocId(forwardIndex.Count);
            docInfo.setTitle(title);
            docInfo.setUrl(url);
            docInfo.setContent(content);
            forwardIndex.Add(docInfo);

            return docInfo;
        }

        public IEnumerable<string> Divide(string term)
        {
            JiebaSegmenter segmenter = new JiebaSegmenter();
            IEnumerable<string> terms = segmenter.Cut(term);
            return terms;
        }

        private void buildInverted(DocInfo docInfo)
        {
            Dictionary<string, WordCount> wordCntHashMap = new Dictionary<string, WordCount>();

            // 1. 针对文档标题进行分词
            IEnumerable<string> terms = Divide(docInfo.getTitle());


            // 2. 遍历分词结果，统计每个词出现的次数
            foreach (string term in terms)
            {
                WordCount wordCount = new WordCount();
                wordCount=wordCntHashMap.GetOrDefault(term);
                if (wordCount == null)
                {
                    // 如果不存在，就创建一个新的键值对，插入进去，titleCount设为 1
                    WordCount wordCount1 = new WordCount();
                    wordCount1.titleCount = 1;
                    wordCount1.contentCount = 0;
                    wordCntHashMap.Add(term, wordCount1);
                }
                else
                {
                    wordCount.titleCount += 1;
                }
            }

            // 3. 针对正文进行分词
            terms = Divide(docInfo.getContent());

            // 4. 遍历分词结果，统计每个词出现的次数
            foreach (string term in terms)
            {
                WordCount wordCount = new WordCount();
                wordCount=wordCntHashMap.GetOrDefault(term);
                if (wordCount == null)
                {
                    // 如果不存在，就创建一个新的键值对，插入进去，contentCount设为 1
                    WordCount wordCount1 = new WordCount();
                    wordCount1.titleCount = 0;
                    wordCount1.contentCount = 1;
                    wordCntHashMap.Add(term, wordCount1);
                }
                else
                {
                    wordCount.contentCount += 1;
                }
            }

            // 5. 把上面的结果汇总到一个 HashMap 里面
            //    最终文档的权重，就设定成 标题中出现的次数*50 + 正文中出现的次数
            // 6. 遍历刚才的 HashMap，依次来更新倒排索引中的结构了
            foreach (KeyValuePair<string, WordCount> entry in wordCntHashMap)
            {
                // 先根据这里的词，去倒排索引中查一查
                // 倒排拉链

                List<Weight> invertedList = invertedIndex.GetOrDefault(entry.Key);
                if (invertedList == null)
                {
                    // 如果为空，就插入一个新的键值对
                    List<Weight> newInvertedList = new List<Weight>();
                    // 把新的文档（当前的 Index.DocInfo)，构造成 Index.Weight 对象，插入进来
                    Weight weight = new Weight();
                    weight.setDocId(docInfo.getDocId());
                    // 权重计算公式，标题中出现的次数*10 + 正文中出现的次数
                    weight.setWeight(entry.Value.titleCount * 50 + entry.Value.contentCount);
                    newInvertedList.Add(weight);
                    invertedIndex.Add(entry.Key, newInvertedList);
                }
                else
                {
                    // 如果非空，就把当前这个文档，构造出一个 Index.Weight 对象，插入到倒排拉链的后面
                    Weight weight = new Weight();
                    weight.setDocId(docInfo.getDocId());
                    weight.setWeight(entry.Value.titleCount * 50 + entry.Value.contentCount);
                    invertedList.Add(weight);
                }
            }
        }
        // 4. 把内存中的索引结构保存到磁盘中
        //public void save()
        //{
        //    Console.WriteLine(forwardIndex.Count);
        //    File.WriteAllText(@"D:\project\Api\Api\resource\project\forward.txt", JsonFormatter.SerializeObject(forwardIndex));
        //    File.WriteAllText(@"D:\project\Api\Api\resource\project\inverted.txt", JsonFormatter.SerializeObject(invertedIndex));    
        //}

        // 5. 把磁盘中的索引结构加载到内存
        //public void load()
        //{
        //    string forward = File.ReadAllText(@"D:\project\Api\Api\resource\project\forward.txt");
        //    forwardIndex = JsonFormatter.DeserializeObject<List<DocInfo>>(forward);
        //    string inverted = File.ReadAllText(@"D:\project\Api\Api\resource\project\inverted.txt");
        //    invertedIndex = JsonFormatter.DeserializeObject<Dictionary<string, List<Weight>>>(inverted);
        //}

    }
}
    
    

